
package cz.czu.pef.DataModelling.beans.common;

import java.io.*;
import java.util.*;

import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.servlet.http.HttpServletRequest;

// TODO: Check whether removing KeepAlive (since it's unsupported in RichFaces 4) will have any effect
//import org.ajax4jsf.model.KeepAlive;

//@KeepAlive
@ManagedBean
@SessionScoped
public class ComponentNavigator implements Serializable
{
	private static final long serialVersionUID = 6830903130097601502L;

	private String lastCompId = null;

	private List<ComponentDescriptor> components = null;

	private ComponentDescriptor currentComponent;

	@SuppressWarnings("rawtypes")
	private List componentGroups = null;

	public boolean getHasCurrentComponent()
	{
		return currentComponent != null;
	}

	public ComponentDescriptor getCurrentComponent()
	{
		String id = getComponentParam("c");
		if (id != null)
		{
			setCurrentComponent(findComponentById(id));
			lastCompId = id;
		}
		else if (lastCompId != null)
		{
			setCurrentComponent(findComponentById(lastCompId));
		}
		else
		{
			String uri = getComponentUri();
			setCurrentComponent(findComponentByUri(uri));
		}

		// set active tab for current component if any
		if (null != currentComponent)
		{
			String tab = getComponentParam("tab");
			if (null != tab)
			{
				currentComponent.setActiveTab(tab);
			}
		}

		return currentComponent;
	}

	private String getComponentUri()
	{
		FacesContext fc = FacesContext.getCurrentInstance();
		return ((HttpServletRequest) fc.getExternalContext().getRequest()).getRequestURI();
	}

	private String getComponentParam(String name)
	{
		FacesContext fc = FacesContext.getCurrentInstance();
		String param = (String) fc.getExternalContext().getRequestParameterMap().get(name);
		if (param != null && param.trim().length() > 0)
		{
			return param;
		}
		else
		{
			return null;
		}
	}

	private List<ComponentDescriptor> components_()
	{
		if (components == null)
		{
			loadComponents();
		}
		return components;
	}

	public ComponentDescriptor findComponentByUri(String uri)
	{
		Iterator<ComponentDescriptor> it = components_().iterator();
		while (it.hasNext())
		{
			ComponentDescriptor component =  it.next();
			if (uri.endsWith(component.getLocation()))
			{
				return component;
			}
		}
		return null;
	}

	public ComponentDescriptor findComponentById(String id)
	{
		Iterator<ComponentDescriptor> it = components_().iterator();
		while (it.hasNext())
		{
			ComponentDescriptor component = it.next();
			if (component.getId().equals(id))
			{
				return component;
			}
		}
		return null;
	}

	public void setCurrentComponent(ComponentDescriptor currentComponent)
	{
		if (currentComponent == null)
		{
			this.currentComponent = (ComponentDescriptor) components_().get(0);
		}
		this.currentComponent = currentComponent;
	}

	@SuppressWarnings("rawtypes")
	public List getComponentGroups()
	{
		return componentGroups;
	}

	public void setComponentGroups(@SuppressWarnings("rawtypes") List componentGroups)
	{
		this.componentGroups = componentGroups;
	}

	private List<ComponentDescriptor> getFilteredComponents(String group)
	{
		List<ComponentDescriptor> ret = new ArrayList<ComponentDescriptor>();
		Iterator<ComponentDescriptor> it = getComponents().iterator();
		while (it.hasNext())
		{
			ComponentDescriptor desc = (ComponentDescriptor) it.next();
			if (desc.getGroup().equals(group))
			{
				ret.add(desc);
			}
		}
		return ret;
	}

	/*
	private boolean checkNewComponents(List<ComponentDescriptor> groups)
	{
		for (ComponentDescriptor component : groups)
		{
			if (component.isNewComponent())
				return true;
		}
		return false;
	}
	*/

	// ************************************************************************************
	public List<ComponentDescriptor> getEntitiesComponents()
	{
		return getFilteredComponents("entities");
	}

	public List<ComponentDescriptor> getEntityViewsComponents()
	{
		return getFilteredComponents("entityViews");
	}

	// ************************************************************************************    
	public List<ComponentDescriptor> getComponents()
	{
		Iterator<ComponentDescriptor> it = components_().iterator();
		ComponentDescriptor cur = getCurrentComponent();
		while (it.hasNext())
		{
			ComponentDescriptor desc = it.next();
			if (desc.equals(cur))
			{
				desc.setCurrent(true);
			}
			else
			{
				desc.setCurrent(false);
			}
		}
		return components;
	}

	public void setComponents(List<ComponentDescriptor> components)
	{
		this.components = components;
	}

	@SuppressWarnings("rawtypes")
	private void loadComponents()
	{
		Properties props = new Properties();
		List<ComponentDescriptor> temp = new ArrayList<ComponentDescriptor>();
		try
		{
			InputStream is = this.getClass().getResourceAsStream("/components.properties");
			props.load(is);
		}
		catch (Exception e)
		{
			throw new FacesException(e);
		}
		Set entries = props.entrySet();
		Iterator it = entries.iterator();
		while (it.hasNext())
		{
			Map.Entry e = (Map.Entry) it.next();
			ComponentDescriptor desc = new ComponentDescriptor();
			desc.setId(e.getKey().toString().trim());
			StringTokenizer toc = new StringTokenizer(e.getValue().toString(), ",");
			// #id=name,captionImage,iconImage,devGuideLocation,tldDocLocation,javaDocLocation
			desc.setGroup(toc.nextToken().trim());
			desc.setName(toc.nextToken().trim());
			desc.setIconImage(toc.nextToken().trim());
			desc.setCaptionImage(toc.nextToken().trim());
			desc.setLocation(toc.nextToken().trim());
			if (toc.hasMoreElements())
				if ("new".equals(toc.nextToken().trim()))
					desc.setNewComponent(true);
				else
					desc.setNewComponent(false);
			temp.add(desc);
		}
		// No sorting (we really want it in the same order as in configuration file)
		/*
		Collections.sort(temp, new Comparator<Object>()
			{
				public int compare(Object o1, Object o2)
				{
					ComponentDescriptor d1 = (ComponentDescriptor) o1;
					ComponentDescriptor d2 = (ComponentDescriptor) o2;
					return d1.getName().compareTo(d2.getName());
				}
			});
		*/
		setComponents(temp);
		setCurrentComponent((ComponentDescriptor) temp.get(0));
	}

	/**
	 * Invoked when example tab panel switched
	 * 
	 * @param event
	 *                a ValueChangeEvent object
	 */
	public void tabPanelSwitched(ValueChangeEvent event)
	{
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
		String viewId = facesContext.getViewRoot().getViewId();
		String actionURL = viewHandler.getActionURL(facesContext, viewId);
		actionURL = patchURL(actionURL, "tab", getCurrentComponent().getActiveTab());
		try
		{
			facesContext.getExternalContext().redirect(actionURL);
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Adds/replaces a query parameter in a given "GET request URL"-like string.
	 *
	 * @param param
	 *                name of query parameter
	 * @param value
	 *                value of query parameter
	 * @return string representing parched url
	 */
	private String patchURL(String url, String param, String value)
	{
		String queryPair = param + "=" + value;
		url.replaceAll("[\\?]" + param + "=[\\w]*", "?" + queryPair);
		url.replaceAll("[&]" + param + "=[\\w]*", "&" + queryPair);

		if (!url.contains("?" + param + "=") && !url.contains("&" + param + "="))
		{
			if (url.contains("?"))
			{
				url += "&";
			}
			else
			{
				url += "?";
			}
			url += queryPair;
		}

		return url;
	}

}
